#pragma once

#include <iostream>
#include <mysql/mysql.h>
#include <sstream>

#include "../common/exception.hpp"
#include "../common/request/add_contact_request.pb.h"
#include "../common/responce/add_contact_responce.pb.h"
#include "../common/responce/find_all_responce.pb.h"
#include "dao/people_info.pb.h"
#include "../common/utils.hpp"

#define MYSQL_HOST "localhost"
#define MYSQL_USER "ubuntu"
#define MYSQL_PASSWORD "20032005LJHly,"
#define MYSQL_DATABASE "web_contacts"
#define MYSQL_PORT 3306
#define UUID_LEN 4

using std::cout;
using std::cin;
using std::endl;
using namespace add_contact_req;
using namespace add_contact_res;
using namespace people_info; 

namespace web_contacts
{
    //表结构
    //uuid phone 序列化信息
    class ContactsMapper
    {
    public:
        //添加一个联系人
        std::string insertContact(const AddContactRequest &req) const
        {
            //连接数据库
            //(1). 初始化
            MYSQL *mysql = nullptr;
            mysql = mysql_init(mysql);
            if(!mysql)
                throw ContactException("sql init error!\n");
            //(2). 连接数据库
            mysql = mysql_real_connect(mysql, MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, nullptr, 0);
            if(!mysql)
                throw ContactException("sql connect error!\n");
            //生成uuid
            std::string uuid = RandomNumber::generate_hex(UUID_LEN);
            //构造联系人
            PeopleInfo people;
            buildPeopleInfo(uuid, &people, req);
            //序列化联系人信息
            std::string info;
            if(!people.SerializeToString(&info))
            {
                //先断开数据库连接
                mysql_close(mysql);
                throw ContactException("addContact people_info SerializeToString error!\n");
            }
            // 转义 info 字段以防止 SQL 注入
            char escaped_info[info.size() * 2 + 1]; // 为转义后的字符串分配足够的空间
            int escaped_length = mysql_real_escape_string(mysql, escaped_info, info.c_str(), info.size());
            std::string safe_info(escaped_info, escaped_length); // 创建转义后的字符串
            //添加联系人————数据库
            std::string sql = "insert into contacts values('" + uuid + "', '" + people.name() + "', '" + safe_info + "');";
            cout << sql << endl;
            if(mysql_query(mysql, sql.c_str()) == 1)
            {
                mysql_close(mysql);
                throw ContactException("insert mysql error!\n");
            }
            printContactInfo(people);
            //返回uuid
            return uuid;
        }

        //查找一个联系人
        std::string findOne(const std::string name) const
        {
            //连接数据库
            MYSQL *mysql = nullptr;
            mysql = mysql_init(mysql);
            if(!mysql)
                throw ContactException("sql init error!\n");
            mysql = mysql_real_connect(mysql, MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, nullptr, 0);
            if(!mysql)
                throw ContactException("sql connect error!\n");
            //查找联系人
            std::string sql = "select * from contacts where name = '" + name + "';"; 
            int n = mysql_query(mysql, sql.c_str());
            if(n == -1)
            {
                mysql_close(mysql);
                throw ContactException("select contact by name error!\n");
            }
            //查看查询结果
            MYSQL_RES *res = mysql_store_result(mysql);
            if(mysql_num_rows(res) == 0)
            {
                mysql_close(mysql);
                throw ContactException("查询的联系人不存在!\n");
            }
            //读取结果
            MYSQL_ROW rows = mysql_fetch_row(res);
            cout << "成功查询联系人 " << name << " uuid: " << rows[0] << endl;
            fflush(stdout);
            return rows[0];
        }

        //删除一个联系人
        void delContact(const std::string &uuid, del_contact_resp::DelContactResponce *resp) const
        {
            //连接数据库
            MYSQL *mysql = nullptr;
            mysql = mysql_init(mysql);
            if(!mysql)
                throw ContactException("mysql init error!\n");
            mysql = mysql_real_connect(mysql, MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, nullptr, 0);
            if(!mysql)
                throw ContactException("mysql connect error!\n");
            //查询联系人
            std::string sql = "select * from contacts where uuid = '" + uuid + "';";
            int n = mysql_query(mysql, sql.c_str());
            if(n == -1)
            {
                mysql_close(mysql);
                throw ContactException("select contacts by uuid error!\n");
            }
            auto res = mysql_store_result(mysql);
            //根据查询结果，构造响应
            if(mysql_num_rows(res) == 0)
            {
                mysql_close(mysql);
                throw ContactException("不存在该联系人!\n");
            }
            //存在该联系人
            MYSQL_ROW rows = mysql_fetch_row(res);
            //构造响应
            if(!resp->mutable_people_info()->ParseFromString(rows[2]))
            {
                mysql_close(mysql);
                throw ContactException("数据库联系人信息反序列化失败!\n");
            }
            //删除联系人
            sql = "delete from contacts where uuid = '" + uuid + "';";
            n = mysql_query(mysql, sql.c_str());
            if(n == -1)
            {
                mysql_close(mysql);
                throw ContactException("delete contacts error!\n");
            }
            mysql_close(mysql);
            cout << "成功删除联系人: " << resp->mutable_people_info()->name() << " uuid: " << uuid << endl;
        }

        //查找所有联系人
        void findAll(find_all_resp::FindAllResponce *resp) const
        {
            //连接数据库
            MYSQL *mysql = nullptr;
            mysql = mysql_init(mysql);
            if(!mysql)
                throw ContactException("mysql init error!\n");
            mysql = mysql_real_connect(mysql, MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, nullptr, 0);
            if(!mysql)
                throw ContactException("mysql connect error!\n");
            //查询所有联系人
            std::string sql = "select uuid, name from contacts;";
            if(mysql_query(mysql, sql.c_str()) == -1){
                mysql_close(mysql);
                throw ContactException("select uuid and name error!\n");
            }
            //获取查询结果
            auto res = mysql_store_result(mysql);
            int rows = mysql_num_rows(res);//有几行
            if(rows == 0){
                mysql_close(mysql);
                throw ContactException("当前联系人为空!\n");
            }
            //构造响应
            for(int i = 0; i < rows; ++i)
            {
                auto line = mysql_fetch_row(res);
                auto people = resp->add_peoples();
                people->set_uuid(line[0]);
                people->set_name(line[1]);
            }
            mysql_close(mysql);
            cout << "客户端请求查询所有联系人" << endl;
        }
    private:
        //将添加联系人的请求转换成联系人
        void buildPeopleInfo(const std::string &uuid, PeopleInfo* people, const AddContactRequest &req) const
        {
            people->set_uuid(uuid);
            //复制信息
            people->set_name(req.name());
            people->set_age(req.age());
            for(auto phone : req.phone())
            {
                PeopleInfo_Phone *copy = people->add_phone();
                copy->set_number(phone.number());
                switch (phone.type())
                {
                case AddContactRequest_Phone_PhoneType_MP:
                    copy->set_type(PeopleInfo_Phone_PhoneType_MP);
                    break;
                case AddContactRequest_Phone_PhoneType_TEL:
                    copy->set_type(PeopleInfo_Phone_PhoneType_MP);
                    break;
                default:
                    break;
                }
            }
            MapCopy::map_copy(people->mutable_remark(), req.remark());
        }
        //打印添加联系人信息
        void printContactInfo(const PeopleInfo& people) const
        {
            cout << "----->成功添加联系人" << endl;
            cout << "uuid: " << people.uuid() << endl;
            cout << "姓名: " << people.name() << endl;
            cout << "年龄: " << people.age() << endl;
            //电话
            for(int i = 0; i < people.phone_size(); ++i)
            {
                const PeopleInfo_Phone &phone = people.phone(i);
                cout << "电话" << i + 1 << endl;
                cout << phone.number() << " (";
                switch (phone.type())
                {
                case AddContactRequest_Phone_PhoneType_MP:
                    cout << "MP)" << endl;
                    break;
                case AddContactRequest_Phone_PhoneType_TEL:
                    cout << "TEL)" << endl;
                    break;
                default:
                    break;
                }
            }
            //备注信息
            for(auto it = people.remark().cbegin(); it != people.remark().cend(); ++it)
                cout << "备注信息标题: " << it->first << endl << "备注信息: " << it->second << endl;
        }
    };
}